# 名称发射器
# 处理 IRName 节点，包括变量名、函数名等

from ...ir.expressions import IRName
from ..core.emitter import EmitResult, NodeTypeEmitter
from ..core.context import CodeGenContext
from ...analysis.type_narrowing import get_wrapper_registry


class NameEmitter(NodeTypeEmitter):
    """名称发射器

    处理变量名和标识符：
    - self -> this
    - 类型收窄后的自动解包
    - 其他名称保持不变
    """

    def __init__(self):
        super().__init__([IRName])
        self.wrapper_registry = get_wrapper_registry()

    def emit(self, node: IRName, context: CodeGenContext) -> EmitResult:
        """生成名称代码"""
        # 1. 检查是否有类型收窄信息（最高优先级）
        narrowing_info = node.get_narrowing_info(node.id)
        if narrowing_info:
            result = self._emit_narrowed_access(node, narrowing_info, context)
            if result:
                return result
        
        # 2. 检查是否是 lambda 参数（在 lambda 体中）
        from mcpy.ir.base import Parameter
        from mcpy.ir.expressions.lambda_expr import IRLambda
        
        symbol = node.lookup_symbol(node.id)
        if symbol and symbol.ir_node and isinstance(symbol.ir_node, Parameter):
            # 检查参数是否属于 lambda
            param_node = symbol.ir_node
            if param_node.parent and isinstance(param_node.parent, IRLambda):
                # 检查是在 operator() 还是 call_impl() 中
                in_operator_call = context.get_extension_param("in_operator_call", False)
                
                if in_operator_call:
                    # 在 operator() 中，直接使用参数名
                    code = node.id
                else:
                    # 在 call_impl() 中，使用 args[i] 访问
                    lambda_arg_index = param_node.get_extension_param("lambda_arg_index")
                    if lambda_arg_index is not None:
                        code = f"args[{lambda_arg_index}]"
                    else:
                        code = node.id  # 保守策略
                
                return EmitResult(code=code, precedence=0)
        
        # 检查是否是 lambda 闭包变量（shared_ref 需要解引用）
        code = self._handle_closure_variable_access(node, context)
        if code:
            return EmitResult(code=code, precedence=0)
        
        # 检查是否是堆分配的嵌套函数（需要包装为 mc::variant）
        code = self._handle_heap_nested_function_ref(node, context)
        if code:
            return EmitResult(code=code, precedence=0)
        
        # self -> this
        if node.id == "self":
            code = "this"
        else:
            code = node.id

        return EmitResult(code=code, precedence=0)

    def _handle_closure_variable_access(self, node: IRName, context: CodeGenContext) -> str | None:
        """处理闭包变量访问（shared_ref 需要解引用）

        Args:
            node: 变量名节点
            context: 代码生成上下文

        Returns:
            如果是 shared_ref 闭包变量返回解引用代码，否则返回 None
        """
        from mcpy.ir.expressions.lambda_expr import IRLambda

        # 检查是否在 lambda 体中
        current = node.parent
        lambda_node = None
        while current:
            if isinstance(current, IRLambda):
                lambda_node = current
                break
            current = current.parent

        if not lambda_node:
            return None  # 不在 lambda 中

        # 检查是否是闭包变量
        if node.id not in (lambda_node.captured_vars or []):
            return None  # 不是闭包变量

        # 检查捕获策略
        capture_strategies = lambda_node.get_extension_param("capture_strategies") or {}
        strategy = capture_strategies.get(node.id)

        if strategy == "shared_ref":
            # shared_ref 需要解引用
            return f"*{node.id}"

        # 其他策略（value, const_ref）直接访问
        return None

    def _handle_heap_nested_function_ref(self, node: IRName, context: CodeGenContext) -> str | None:
        """处理堆分配嵌套函数的引用

        注意：由于嵌套函数定义已经生成为变量赋值（mc::variant add = ...），
        这里只需要直接返回变量名，不需要重新包装。

        Args:
            node: 变量名节点
            context: 代码生成上下文

        Returns:
            None（现在嵌套函数已经是变量，直接使用名称即可）
        """
        # 不再需要特殊处理，嵌套函数定义已经生成为变量赋值
        return None

    def _emit_narrowed_access(self, node: IRName, narrowing_info, context: CodeGenContext) -> EmitResult | None:
        """生成收窄后的变量访问代码
        
        根据类型收窄信息和解包策略，自动插入解包代码：
        - Optional[T] -> T: num.value()
        - Any -> T: any_val.as<int>()
        - Union[T1,T2] -> T1: union_val.as<string>()
        
        Args:
            node: 变量名节点
            narrowing_info: 类型收窄信息
            context: 代码生成上下文
        
        Returns:
            EmitResult，如果无法处理则返回 None
        """
        var_name = node.id
        
        # 检查是否是包装类型（Optional, unique_ptr 等）
        if self.wrapper_registry.is_wrapper_type(narrowing_info.original_type):
            # 从注册表查询解包策略
            use_context = self._determine_use_context(node, context)
            strategy = self.wrapper_registry.get_unwrap_strategy(
                narrowing_info.original_type, 
                use_context
            )
            
            if strategy:
                # 应用解包模板：num -> num.value()
                pattern = strategy["pattern"]
                precedence = strategy["precedence"]
                code = pattern.replace("{self}", var_name)
                return EmitResult(code=code, precedence=precedence)
        
        # 非包装类型：Any -> T, Union -> T
        # 使用类型转换：x -> x.as<int>()
        if narrowing_info.narrowing_kind in ["any_cast", "union_discriminate"]:
            from ...type_system import get_cpp_type
            cpp_type = get_cpp_type(narrowing_info.narrowed_type, node)
            if cpp_type:
                code = f"{var_name}.as<{cpp_type}>()"
                return EmitResult(code=code, precedence=2)  # . 运算符优先级
        
        return None
    
    def _determine_use_context(self, node: IRName, context: CodeGenContext) -> str:
        """确定变量的使用上下文
        
        返回：
        - "value_context": 需要值（如算术运算、函数参数）
        - "member_access": 成员访问（如 ptr.method()）
        - "always": 任何上下文
        
        Args:
            node: 变量名节点
            context: 代码生成上下文
        
        Returns:
            使用上下文字符串
        """
        from ...ir import IRAttribute, IRBinOp, IRAssign
        
        # 检查父节点
        parent = node.parent
        
        if isinstance(parent, IRAttribute):
            # ptr.name -> member_access
            if parent.value == node:
                return "member_access"
        
        elif isinstance(parent, IRBinOp):
            # ptr + 1 -> value_context
            return "value_context"
        
        elif isinstance(parent, IRAssign):
            # x = ptr -> 可能需要直接使用
            if parent.value == node:
                # 赋值右侧，默认需要值
                return "value_context"
        
        # 默认：需要值
        return "value_context"

    def get_priority(self) -> int:
        """名称发射器的优先级"""
        return 60  # 较高优先级，优先于 LiteralEmitter，以处理 lambda 参数等特殊情况
